import 'dart:io';

import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart' hide FormData, Response, MultipartFile;
import 'package:path_provider/path_provider.dart';

import '../values/constants.dart';
import '../models/index.dart';
import '../utils/toast_util.dart';

/*
* HTTP工具类
* 
* 1. 支持请求配置
* 2. 统一日志输出
* 3. 统一异常处理
* 4. Token鉴权
* 5. 请求取消
*/

class HttpService extends GetxService {
  static HttpService get to => Get.find();

  late final Dio _dio;
  late final CancelToken _cancelToken;
  late final CookieJar _cookieJar;

  // 错误信息防重复显示
  final Set<String> _shownErrors = {};

  @override
  void onInit() {
    super.onInit();
    _initDio();
  }

  // 初始化Dio
  Future<void> _initDio() async {
    // 创建Dio实例
    _dio = Dio(
      BaseOptions(
        baseUrl: Constants.apiBaseUrl,
        connectTimeout: const Duration(seconds: 10),
        receiveTimeout: const Duration(seconds: 10),
        headers: {},
        contentType: 'application/json; charset=utf-8',
        responseType: ResponseType.json,
        followRedirects: true, // 允许自动跟踪重定向
        maxRedirects: 5, // 最多5次重定向
        // 🔧 修复307重定向问题：允许所有2xx和3xx状态码
        validateStatus: (status) {
          return status != null && status >= 200 && status < 400;
        },
      ),
    );

    // 创建取消令牌
    _cancelToken = CancelToken();

    // 初始化Cookie管理器
    Directory tempDir = await getTemporaryDirectory();
    _cookieJar = PersistCookieJar(
      ignoreExpires: true,
      storage: FileStorage("${tempDir.path}/cookies/"),
    );

    // 添加拦截器
    _dio.interceptors.add(CookieManager(_cookieJar));
    _dio.interceptors.add(_RequestInterceptor());
    _dio.interceptors.add(_ResponseInterceptor());
    _dio.interceptors.add(_ErrorInterceptor());

    // 是否启用调试模式
    if (kDebugMode) {
      _dio.interceptors.add(
        LogInterceptor(requestBody: true, responseBody: true),
      );
    }
  }

  // 清除错误记录，用于切换页面时重置
  void clearErrorCache() {
    _shownErrors.clear();
  }

  // 是否已显示错误
  bool hasShownError(String path) {
    return _shownErrors.contains(path);
  }

  // 添加已显示错误
  void addShownError(String path) {
    _shownErrors.add(path);

    // 60秒后自动清除，避免长时间缓存
    Future.delayed(const Duration(seconds: 60), () {
      _shownErrors.remove(path);
    });
  }

  // GET请求
  Future<T> get<T>(
    String path, {
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool refresh = false,
    bool noCache = false,
    bool showError = true,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.extra ??= {};
    requestOptions.extra!.addAll({
      "refresh": refresh,
      "noCache": noCache,
      "showError": showError,
    });

    Response response = await _dio.get(
      path,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    return response.data;
  }

  // POST请求
  Future<T> post<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool showError = true,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.extra ??= {};
    requestOptions.extra!.addAll({"showError": showError});

    Response response = await _dio.post(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    return response.data;
  }

  // PUT请求
  Future<T> put<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool showError = true,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.extra ??= {};
    requestOptions.extra!.addAll({"showError": showError});

    Response response = await _dio.put(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    return response.data;
  }

  // DELETE请求
  Future<T> delete<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool showError = true,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.extra ??= {};
    requestOptions.extra!.addAll({"showError": showError});

    Response response = await _dio.delete(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    return response.data;
  }

  // 上传文件
  Future<T> upload<T>(
    String path, {
    required FormData data,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    bool showError = true,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.extra ??= {};
    requestOptions.extra!.addAll({"showError": showError});

    Response response = await _dio.post(
      path,
      data: data,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
      onSendProgress: onSendProgress,
    );
    return response.data;
  }

  // 下载文件
  Future<Response> download(
    String url,
    String savePath, {
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
    bool showError = true,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.extra ??= {};
    requestOptions.extra!.addAll({"showError": showError});

    Response response = await _dio.download(
      url,
      savePath,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
      onReceiveProgress: onReceiveProgress,
    );
    return response;
  }

  // 取消所有请求
  void cancelRequests() {
    _cancelToken.cancel("取消所有请求");
  }

  // 清除Cookie
  Future<void> clearCookies() async {
    await _cookieJar.deleteAll();
  }
}

// 请求拦截器
class _RequestInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    // 在这里添加Token等请求头
    // 例如:
    // final token = UserStore.to.token;
    // if (token.isNotEmpty) {
    //   options.headers['Authorization'] = 'Bearer $token';
    // }

    debugPrint('REQUEST[${options.method}] => PATH: ${options.path}');
    return handler.next(options);
  }
}

// 响应拦截器
class _ResponseInterceptor extends Interceptor {
  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    // 统一处理响应数据
    // 这里可以根据项目API的统一格式进行处理
    // 例如: { "code": 200, "msg": "success", "data": {} }

    if (response.statusCode == 200 || response.statusCode == 201) {
      // 示例: 提取data字段作为实际需要的数据
      // if (response.data['code'] == 200) {
      //   response.data = response.data['data'];
      // } else {
      //   throw ApiException(
      //     response.data['code'],
      //     response.data['msg'],
      //   );
      // }
    }

    // 🔧 添加响应数据类型日志，帮助调试
    debugPrint(
      'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}',
    );
    debugPrint('Response data type: ${response.data.runtimeType}');
    if (response.data is String && (response.data as String).length < 200) {
      debugPrint('Response Text:\n${response.data}');
    }
    return handler.next(response);
  }
}

// 错误拦截器
class _ErrorInterceptor extends Interceptor {
  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    // 统一处理错误
    ApiException apiException = ApiException.fromDioError(err);

    // 获取请求路径
    final String path = err.requestOptions.path;

    // 检查是否需要显示错误
    final bool showError = err.requestOptions.extra['showError'] ?? true;

    // 如果需要显示错误，且该错误未被显示过，则显示错误
    if (showError && !HttpService.to.hasShownError(path)) {
      // 标记该错误已显示
      HttpService.to.addShownError(path);

      // 弹出错误消息
      ToastUtil.error('错误 - ${apiException.message}');
    }

    // 打印错误日志
    debugPrint('ERROR[${apiException.code}] => PATH: $path');
    debugPrint(apiException.message);

    // 继续传递错误
    handler.next(err);
  }
}
